﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ShredTheLog.Api;
using System.Windows.Input;
using ShredTheLog.Api.DataContracts;
using System.ComponentModel.Composition;
using System.Diagnostics.Contracts;
using ShredTheLog.Translation;
using ShredTheLog.Model;

namespace ShredTheLog.Plugins
{
    [Export(typeof(IShredSettings))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Serializable]
    public sealed class ShredSettings : IShredSettings
    {
        [ImportMany]
        public ISettingsSection[] Sections { get; private set; }

        public void Assign(object obj)
        {
            var o = (ShredSettings)obj;
            var conjugateSections =
                from s1 in Sections
                join s2 in o.Sections on s1.GetType() equals s2.GetType()
                select new { S1 = s1, S2 = s2 };

            conjugateSections.ForEach(i => i.S1.Assign(i.S2));
        }
    }

    [Export(typeof(IUiSettingsSection))]
    [Export(typeof(ISettingsSection))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Serializable]
    public sealed class UiSettingsSection : IUiSettingsSection
    {
        [ImportMany]
        [NonSerialized]
        private IUiLanguage[] _uiLanguages = null;

        [ImportMany]
        [NonSerialized]
        private ITheme[] _themes = null;

        private static readonly KeyGestureConverter KeyGestureConverter = new KeyGestureConverter();

        public UiSettingsSection()
        {
            ThemeID = "Flash";
            UiLanguage = Language.English;
            SendMessageGesture = new KeyGesture(Key.Enter, ModifierKeys.Control);
            SendTypingNotifications = true;
            ShowMessageTime = true;
        }

        public string ThemeID { get; set; }

        public ITheme GetTheme()
        {
            Contract.Assume(_themes != null);
            var result = _themes.Single(i => i.ID == ThemeID);
            Contract.Assume(result != null);
            return result;
        }

        public Language UiLanguage { get; set; }

        public IUiLanguage GetUiLanguage()
        {
            Contract.Assume(_uiLanguages != null);
            var result = _uiLanguages.Single(i => i.Language == UiLanguage);
            Contract.Assume(result != null);
            return result;
        }

        private string _sendMessageGestureString;

        public KeyGesture SendMessageGesture
        {
            get 
            { 
                return 
                    !String.IsNullOrEmpty(_sendMessageGestureString) ? 
                    (KeyGesture)KeyGestureConverter.ConvertFromInvariantString(_sendMessageGestureString) : 
                    null; 
            }
            set 
            { 
                _sendMessageGestureString = KeyGestureConverter.ConvertToInvariantString(value); 
            }
        }

        public bool SendTypingNotifications { get; set; }

        public bool ShowMessageTime { get; set; }

        public void Assign(object obj)
        {
            var o = (UiSettingsSection)obj;
            ThemeID = o.ThemeID;
            UiLanguage = o.UiLanguage;
            SendMessageGesture = o.SendMessageGesture;
            SendTypingNotifications = o.SendTypingNotifications;
            ShowMessageTime = o.ShowMessageTime;
        }
    }

    [Export(typeof(IConnectionSettingsSection))]
    [Export(typeof(ISettingsSection))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Serializable]
    public sealed class ConnectionSettingsSection : IConnectionSettingsSection
    {
        private const string DefaultServer = "http://sharedtalk.com";

        public ConnectionSettingsSection()
        {
            UseDefaultConnectionSettings = true;
            BaseServer = DefaultServer;
            TextChatServer = DefaultServer;
        }

        private bool _useDefaultConnectionSettings;
        public bool UseDefaultConnectionSettings
        {
            get
            {
                return _useDefaultConnectionSettings;
            }
            set
            {
                _useDefaultConnectionSettings = value;
                _client = null;
            }
        }

        private string _baseServer;
        public string BaseServer 
        { 
            get 
            {
                Contract.Assume(!String.IsNullOrWhiteSpace(_baseServer));
                return _baseServer; 
            } 
            set 
            { 
                _baseServer = value; 
                _client = null; 
            } 
        }

        private string _textChatServer;
        public string TextChatServer 
        {
            get 
            {
                Contract.Assume(!String.IsNullOrWhiteSpace(_textChatServer));
                return _textChatServer; 
            }
            set
            {
                _textChatServer = value;
                _client = null;
            }
        }

        public string UserName { get; set; }

        public string Password { get; set; }

        [NonSerialized]
        private IShredClient _client;

        public IShredClient GetClient()
        {
            if (_client == null)
            {
                if (UseDefaultConnectionSettings)
                    _client = new ShredClient(DefaultServer, DefaultServer);
                else
                    _client = new ShredClient(BaseServer, TextChatServer);
            }
            return _client;
        }

        public void Assign(object obj)
        {
            var o = (ConnectionSettingsSection)obj;
            UseDefaultConnectionSettings = o.UseDefaultConnectionSettings;
            BaseServer = o.BaseServer;
            TextChatServer = o.TextChatServer;
            UserName = o.UserName;
            Password = o.Password;
        }
    }

    [Export(typeof(ITranslatorSettingsSection))]
    [Export(typeof(ISettingsSection))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Serializable]
    public sealed class TranslatorSettingsSection : ITranslatorSettingsSection
    {
        [ImportMany]
        [NonSerialized]
        private ITranslator[] _translators = null;

        [Import]
        [NonSerialized]
        private IUiSettingsSection _uiSettings = null;

        [NonSerialized]
        private ITranslatorBase _translator;

        [NonSerialized]
        private ITranslatorBase _filteringTranslator;

        public TranslatorSettingsSection()
        {
            IsActive = true;
            TranslatorID = GoogleTranslator.IDString;
            TargetLanguage = Language.English;
            IsUiLanguageTarget = true;
        }

        public bool IsActive { get; set; }

        private string _translatorID;
        public string TranslatorID 
        {
            get 
            {
                Contract.Assume(!String.IsNullOrWhiteSpace(_translatorID));
                return _translatorID; 
            }
            set
            {
                _translatorID = value;
                _translator = null;
                _filteringTranslator = null;
            }
        }

        public ITranslatorBase GetTranslator()
        {
            if (_translator == null)
            {
                var innerTranslator = _translators.Single(i => i.ID == TranslatorID);
                Contract.Assume(innerTranslator != null);
                _translator = new CachingTranslator(innerTranslator);
            }
            return _translator;
        }

        public ITranslatorBase GetFilteringTranslator()
        {
            if (_filteringTranslator == null)
                _filteringTranslator = new FilteringTranslator(GetTranslator());
            return _filteringTranslator;
        }

        public bool IsUiLanguageTarget { get; set; }

        public Language TargetLanguage { get; set; }

        public Language GetTargetLanguage()
        {
            return IsUiLanguageTarget ? _uiSettings.UiLanguage : TargetLanguage;
        }

        public void Assign(object obj)
        {
            var o = (TranslatorSettingsSection)obj;
            IsActive = o.IsActive;
            TranslatorID = o.TranslatorID;
            TargetLanguage = o.TargetLanguage;
            IsUiLanguageTarget = o.IsUiLanguageTarget;
        }
    }

    [Export(typeof(INotificationSettingsSection))]
    [Export(typeof(ISettingsSection))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Serializable]
    public sealed class NotificationSettingsSection : INotificationSettingsSection
    {
        [ImportMany]
        public INotifierSettings[] Settings { get; private set; }

        public void Assign(object obj)
        {
            var o = (NotificationSettingsSection)obj;
            var settingSets =
                from src in o.Settings
                from dst in Settings
                where src.GetType() == dst.GetType()
                select new { Src = src, Dst = dst };
            settingSets.ForEach(i => i.Dst.Assign(i.Src));
        }
    }

    [Export(typeof(ISoundNotifierSettings))]
    [Export(typeof(INotifierSettings))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Serializable]
    public sealed class SoundNotifierSettings : ISoundNotifierSettings
    {
        public SoundNotifierSettings()
        {
            IsActive = true;
            NotifyOnMessagesInActiveChatWindows = true;
            NotifyOnPublicChatMessages = true;
        }

        public bool IsActive { get; set; }
        public bool NotifyOnMessagesInActiveChatWindows { get; set; }
        public bool NotifyOnPublicChatMessages { get; set; }

        public void Assign(object obj)
        {
            var o = (SoundNotifierSettings)obj;
            IsActive = o.IsActive;
            NotifyOnMessagesInActiveChatWindows = o.NotifyOnMessagesInActiveChatWindows;
            NotifyOnPublicChatMessages = o.NotifyOnPublicChatMessages;
        }

        public object Clone()
        {
            var result = new SoundNotifierSettings();
            result.Assign(this);
            return result;
        }
    }

    [Export(typeof(IFlashWindowNotifierSettings))]
    [Export(typeof(INotifierSettings))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Serializable]
    public sealed class FlashWindowNotifierSettings : IFlashWindowNotifierSettings
    {
        public FlashWindowNotifierSettings()
        {
            IsActive = true;
            NotifyOnMessagesInActiveChatWindows = false;
            NotifyOnPublicChatMessages = false;
        }

        public bool IsActive { get; set; }
        public bool NotifyOnMessagesInActiveChatWindows { get; set; }
        public bool NotifyOnPublicChatMessages { get; set; }

        public void Assign(object obj)
        {
            var o = (FlashWindowNotifierSettings)obj;
            IsActive = o.IsActive;
            NotifyOnMessagesInActiveChatWindows = o.NotifyOnMessagesInActiveChatWindows;
            NotifyOnPublicChatMessages = o.NotifyOnPublicChatMessages;
        }

        public object Clone()
        {
            var result = new FlashWindowNotifierSettings();
            result.Assign(this);
            return result;
        }
    }

    [Export(typeof(IBalloonTipNotifierSettings))]
    [Export(typeof(INotifierSettings))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Serializable]
    public sealed class BalloonTipNotifierSettings : IBalloonTipNotifierSettings
    {
        public BalloonTipNotifierSettings()
        {
            IsActive = true;
            NotifyOnMessagesInActiveChatWindows = false;
            NotifyOnPublicChatMessages = false;
        }

        public bool IsActive { get; set; }
        public bool NotifyOnMessagesInActiveChatWindows { get; set; }
        public bool NotifyOnPublicChatMessages { get; set; }

        public void Assign(object obj)
        {
            var o = (BalloonTipNotifierSettings)obj;
            IsActive = o.IsActive;
            NotifyOnMessagesInActiveChatWindows = o.NotifyOnMessagesInActiveChatWindows;
            NotifyOnPublicChatMessages = o.NotifyOnPublicChatMessages;
        }

        public object Clone()
        {
            var result = new BalloonTipNotifierSettings();
            result.Assign(this);
            return result;
        }
    }
}
